CAMEL-24070: camel-spring-rabbitmq - Fix thread-unsafe lazy template creation in SpringRabbitMQProducer - #24727
Conversation
…creation in SpringRabbitMQProducer Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Claus Ibsen <claus.ibsen@gmail.com>
gnodet
left a comment
There was a problem hiding this comment.
Clean thread-safety fix — the race in lazy template creation is real and the ReentrantLock approach is correct.
What works well:
- Lock pattern matches the existing
EndpointMessageListener.getTemplate()in this same component — consistent. inOutTemplate.start()moved inside the null-check is an important secondary fix: previously everygetInOutTemplate()call re-started the template, which is wasteful and potentially confusing.doStop()also guarded by the lock — prevents a race between a lateprocess()call and shutdown.Boolean.FALSE == sent→!sentis a good cleanup (identity comparison on autoboxed primitive).- The test design with a
CountDownLatchbarrier maximises contention to expose the race.
Checklist:
- Tests included (8-thread concurrent access test)
- No public API changes
- Thread-safety — lock scope is correct (covers check-then-act on both getters + stop)
- No
@authortags - CI — builds pending
Reviewed with Claude Code on behalf of gnodet. This review was generated by an AI agent and may contain inaccuracies; please verify all suggestions before applying.
|
🌟 Thank you for your contribution to the Apache Camel project! 🌟 🐫 Apache Camel Committers, please review the following items:
|
|
🧪 CI tested the following changed modules:
🔬 Scalpel shadow comparison — Scalpel: 9 tested, 29 compile-only — current: 9 all testedMaveniverse Scalpel detected 38 affected modules (current approach: 9).
|
Summary
Claude Code on behalf of davsclaus
SpringRabbitMQProducerlazily creates itsRabbitTemplateandAsyncRabbitTemplatewithout synchronization. Since a producer is a singleton invoked concurrently by route threads, concurrent first messages can each create their own template; all but the last assignment are dropped without being stopped. In the InOut case each racing thread also starts its template, so the losers are leaked in started state.Changes
ReentrantLockto guardgetInOnlyTemplate(),getInOutTemplate(), anddoStop()— same pattern already used byEndpointMessageListener.getTemplate()in this componentinOutTemplate.start()inside the null-check so it is only called once on creation, not on every invocationBoolean.FALSE == sentidentity comparison on a primitive boolean to!sentSpringRabbitMQProducerThreadSafetyTestthat verifies concurrentgetInOnlyTemplate()calls from 8 threads always return the same instanceFixes: CAMEL-24070
Test plan
SpringRabbitMQProducerThreadSafetyTestpasses — 8 threads behind a barrier all get the same template instance